`include "common_def.v"
`include "decode_def.v"
module MODULE_EXU(
	input									clk_i,
	input									rst_i,
	input									ELSp_ready_i,
	output								exe_ready_o,
//connect with CTR
	input									exe_start_i,
	output								exe_end_o,
//connect with  REGS
	input		[`WIDTH-1:0]	src1_i,
	input		[`WIDTH-1:0]	src2_i,
	input		[`WIDTH-1:0]	csr_i,
	input		[`WIDTH-1:0]	pc_i,
	output 	[`WIDTH-1:0]	data_dst_o,//data to write in the regs
	output	[`WIDTH-1:0]  data_csr_o,//data write to csrs
	output	[`WIDTH-1:0]	npc_o,
//connect with IDU
	input		[`WIDTH-1:0]	imm_i,
	input		[`OP_NUM-1:0]	alu_key_i,
	input		[1:0]					mul_sign_key_i,
	input		[`A_NUM-1:0]	alu_A_key_i,
	input		[`B_NUM-1:0]	alu_B_key_i,
	input		[`SHAMT_NUM-1:0]shamt_key_i,
	input		[`PC_NUM-1:0]	pc_key_i,
	input									alu_result_key_i,
	input 	[`RESULT_NUM-1:0]result_key_i,
	input  	[`CSR_KEY_NUM-1:0]data_csr_key_i,	
	input									csr_i_or_r_key_i,
//connect with MEM_CTR
	output	[`WIDTH-1:0]	address_o
);

assign exe_ready_o = ELSp_ready_i;

wire [`WIDTH-1:0] 			A;
wire [`WIDTH-1:0] 			B;
wire [`WIDTH-1:0]				Result;
wire [`WIDTH-1:0]				alu_64bit_result;
//not used yet
//wire										Carry;
//wire 										Zero;
//wire 										Overflow;
//first number send to alu
MuxKeyWithDefault #(`A_NUM,`A_NUM,`WIDTH) A_mux (A[`WIDTH-1:0],alu_A_key_i[`A_NUM-1:0],{`WIDTH{1'b0}},{
	4'b0001, src1_i[`WIDTH-1:0],
	4'b0010,	pc_i[`WIDTH-1:0],//pc
	4'b0100,{`WIDTH{1'b0}},	//0
	4'b1000,{{`WIDTH-32{1'b0}},{src1_i[31:0]}}	
});
//second number send to alu
wire [`WIDTH-1:0]				B_before_shamt_mux;
MuxKeyWithDefault #(`B_NUM,`B_NUM,`WIDTH) B_before_cut_mux (B_before_shamt_mux[`WIDTH-1:0],alu_B_key_i[`B_NUM-1:0],{`WIDTH{1'b0}},{
	2'b01, imm_i[`WIDTH-1:0],
	2'b10, src2_i[`WIDTH-1:0]
});
MuxKeyWithDefault #(`SHAMT_NUM,`SHAMT_NUM,`WIDTH) B_mux (B[`WIDTH-1:0],shamt_key_i[`SHAMT_NUM-1:0],B_before_shamt_mux[`WIDTH-1:0],{
	2'b01, {{`WIDTH-5{1'b0}},B_before_shamt_mux[4:0]}, 
	2'b10, {{`WIDTH-6{1'b0}},B_before_shamt_mux[5:0]}	
});

MODULE_ALU alu (
.clk_i									(clk_i),
.rst_i									(rst_i),
.valid_i								(exe_start_i),
.A_i										(A),
.B_i										(B),
.key_i									(alu_key_i),
.mul_sign_key_i					(mul_sign_key_i[1:0]),
.Result_o								(alu_64bit_result),
.result_valid_o					(exe_end_o)
//.Carry_o								(Carry),
//.Zero_o									(Zero),
//.Overflow_o							(Overflow)
);

//decide if choose the low 32 bit and sign ex as the real result of the cal;
assign Result[`WIDTH-1:0] = alu_result_key_i ? {{32{alu_64bit_result[31]}},alu_64bit_result[31:0]}:alu_64bit_result[`WIDTH-1:0];
//decide the address to MEMCTR for load and store
assign address_o[`WIDTH-1:0] = Result[`WIDTH-1:0];

//decide data_dst_o default use alu_result 
MuxKeyWithDefault #(`RESULT_NUM,`RESULT_NUM,`WIDTH) data_dst_o_mux(data_dst_o[`WIDTH-1:0],result_key_i[`RESULT_NUM-1:0],Result[`WIDTH-1:0],{
	2'b01,	pc_i[`WIDTH-1:0]+4,
	2'b10, csr_i[`WIDTH-1:0]
});
//decide data_csr_o
//assign data_csr_o[`WIDTH-1:0] = data_csr_key_i ? src1_i[`WIDTH-1:0]:(src1_i[`WIDTH-1:0]|csr_i[`WIDTH-1:0]); 
MuxKeyWithDefault #(`CSR_KEY_NUM,`CSR_KEY_NUM,`WIDTH) csr_data_mux (data_csr_o[`WIDTH-1:0],data_csr_key_i[`CSR_KEY_NUM-1:0],0,{
	3'b001, csr_i_or_r_key_i ? imm_i[`WIDTH-1:0] : src1_i[`WIDTH-1:0], 
	3'b010, csr_i[`WIDTH-1:0] | (csr_i_or_r_key_i ? imm_i[`WIDTH-1:0] : src1_i[`WIDTH-1:0]),
	3'b100, csr_i[`WIDTH-1:0] & (~(csr_i_or_r_key_i ? imm_i[`WIDTH-1:0] : src1_i[`WIDTH-1:0]))
});

//about new pc
MuxKeyWithDefault #(`PC_NUM,`PC_NUM,`WIDTH) npc_mux (npc_o[`WIDTH-1:0],pc_key_i[`PC_NUM-1:0],pc_i[`WIDTH-1:0]+4,{
	3'b001, Result[`WIDTH-1:0], 
	3'b010, {Result[`WIDTH-1:1],1'b0},
	3'b100, csr_i[`WIDTH-1:0]
});
endmodule
